﻿$import( "SmitearWebGL.Objects.Container" );

SmitearWebGL.Objects.Entity = SmitearWebGL.Objects.Container.extend(
{
	/******** constructor ********/

	init : function()
	{
		/******** public property ********/

		/******** private property ********/

		this._displayType = SmitearWebGL.Objects.Entity.DisplayType.ENTITY;
		this._position = null;
		this._rotation = null;
		this._scale = null;
		this._quaternion = null;
		this._transformMatrix = null;
		this._worldMatrix = null;
		this._invWorldViewMatrix = null;
		this._worldViewMatrix = null;
		this._normalViewMatrix = null;
		this._projectionMatrix = null;
		this._worldViewProjMatrix = null;
		this._status = null;
		
		this._super();
		this._registClass( "SmitearWebGL.Objects.Entity" );
	}
	,

	/******** public method ********/
	
	glUniform : function( field, shader )
	{
		switch( field )
		{
			case SmitearWebGL.ShaderUniform.projectionMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uProjectionMatrix.location, false, new Float32Array( this._projectionMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.invPerspectiveMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uInvPerspectiveMatrix.location, false, new Float32Array( this._invProjectionMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.worldMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uWorldMatrix.location, false, new Float32Array( this._worldMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.worldViewMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uWorldViewMatrix.location, false, new Float32Array( this._worldViewMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.invWorldViewMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uInvWorldViewMatrix.location, false, new Float32Array( this._invWorldViewMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.normalMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uNormalViewMatrix.location, false, new Float32Array( this._normalViewMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.normalViewMatrix:
				this.context.gl.uniformMatrix4fv( shader.uniforms.uNormalViewMatrix.location, false, new Float32Array( this._normalViewMatrix.flatten() ) );
				break;
				
			case SmitearWebGL.ShaderUniform.viewMatrix:
				//not used
				break;
		}
	}
	,
	getDisplayType : function()
	{
		return this._displayType;
	}
	,
	setX : function( value )
	{
		if ( this._position.x == value )
			return;
			
		this._position.x = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setY : function( value )
	{
		if ( this._position.y == value )
			return;
			
		this._position.y = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setZ : function( value )
	{
		if ( this._position.z == value )
			return;
			
		this._position.z = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	getX : function()
	{
		return this._position.x;
	}
	,
	getY : function()
	{
		return this._position.y;
	}
	,
	getZ : function()
	{
		return this._position.z;
	}
	,
	setRotationX : function( value )
	{
		this._rotation.x = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setRotationY : function( value )
	{
		this._rotation.y = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setRotationZ : function( value )
	{
		this._rotation.z = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	getRotationX : function()
	{
		return this._rotation.x;
	}
	,
	getRotationY : function()
	{
		return this._rotation.y;
	}
	,
	getRotationZ : function()
	{
		return this._rotation.z;
	}
	,
	setScaleX : function( value )
	{
		if ( this._scale.x == value )
			return;
			
		this._scale.x = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setScaleY : function( value )
	{
		if ( this._scale.y == value )
			return;
			
		this._scale.y = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setScaleZ : function( value )
	{
		if ( this._scale.z == value )
			return;
			
		this._scale.z = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	setScale : function( value )
	{
		if ( this._scale.x == value &&
			this._scale.y == value &&
			this._scale.z == value )
			return;
		
		this._scale.x = value;
		this._scale.y = value;
		this._scale.z = value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	getScaleX : function()
	{
		return this._scale.x;
	}
	,
	getScaleY : function()
	{
		return this._scale.y;
	}
	,
	getScaleZ : function()
	{
		return this._scale.z;
	}
	,
	forward : function( value )
	{
		this._position.z -= value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	backward : function( value )
	{
		this._position.z += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	rightward : function( value )
	{
		this._position.x += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	leftward : function( value )
	{
		this._position.x -= value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	upward : function( value )
	{
		this._position.y += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	downward : function( value )
	{
		this._position.y -= value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	rotateX : function( value )
	{
		this._rotation.x += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	rotateY : function( value )
	{
		this._rotation.y += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	rotateZ : function( value )
	{
		this._rotation.z += value;
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	isTransformDirty : function()
	{
		return this._status.testBit( SmitearWebGL.Objects.Entity.nTransformDirty );
	}
	,
	isViewDirty : function()
	{
		return this._status.testBit( SmitearWebGL.Objects.Entity.nViewDirty );
	}
	,
	isTransformed : function()
	{
		return this._status.testBit( SmitearWebGL.Objects.Entity.nTransformed );
	}
	,
	updateTransform : function()
	{
		if ( this.isTransformed() ) return;
		
		var camera = this._scene._renderSession.camera;
		var parentDirty = false;
		var cameraDirty = camera.isTransformDirty();
		var dirty = this.isTransformDirty();
		
		if ( this._parent )
		{
			this._parent.updateTransform();
			parentDirty = this._parent.isViewDirty();
		}
		
		if ( dirty )
		{
			parentDirty = true;
			
			this._quaternion.setFromYawPitchRoll( this._rotation.y * SmitearWebGL.Core.Math.toRADIANS,
												this._rotation.x * SmitearWebGL.Core.Math.toRADIANS,
												this._rotation.z * SmitearWebGL.Core.Math.toRADIANS );

			this._transformMatrix.identity();
			this._transformMatrix.calculateMultiply( SmitearWebGL.Core.Math.Matrix4x4.scale( this._scale.x, this._scale.y, this._scale.z ), this._transformMatrix );
			this._transformMatrix.calculateMultiply( this._quaternion.getMatrix(), this._transformMatrix );
			this._transformMatrix.calculateMultiply( SmitearWebGL.Core.Math.Matrix4x4.translation( this._position.x, this._position.y, this._position.z ), this._transformMatrix );
		}

		if ( parentDirty )
		{
			cameraDirty = true;
			
			if ( this._parent )
				this._worldMatrix.calculateMultiply( this._parent._worldMatrix, this._transformMatrix );
			else
				this._worldMatrix.copy( this._transformMatrix );
		}
		
		this._projectionMatrix.copy4x4( camera.getProjectionMatrix() );
		this._invProjectionMatrix.copy4x4( camera.getInvProjectionMatrix() );

		if ( cameraDirty )
		{
			this._worldViewMatrix.calculateMultiply( camera._viewMatrix, this._worldMatrix );
			this._invWorldViewMatrix.calculateInverse4x4( this._worldViewMatrix );
			
			this._normalViewMatrix.copy4x4( this._invWorldViewMatrix );
			this._normalViewMatrix.calculateTranspose();
			
			this._worldViewProjMatrix.calculateMultiply4x4( this._projectionMatrix, this._worldViewMatrix );
		}
			
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformed, true );
		this._status.setBit( SmitearWebGL.Objects.Entity.nViewDirty, dirty || parentDirty || cameraDirty );
	}
	,
	updateBeforeRender : function()
	{
	}
	,
	updateAfterRender : function()
	{
		this._status.clear();
	}
	,
	_createResource : function( params )
	{
		this._super();

		this._displayType = SmitearWebGL.Objects.Entity.DisplayType.ENTITY;
		this._position = $V3( 0.0, 0.0, 0.0 );
		this._rotation = $V3( 0.0, 0.0, 0.0 );
		this._scale = $V3( 1.0, 1.0, 1.0 );
		this._quaternion = $Q( 0.0, 0.0, 0.0, 1.0 );
		
		this._transformMatrix = $M4x4();
		this._worldMatrix = $M4x4();
		this._invWorldViewMatrix = $M4x4();
		this._worldViewMatrix = $M4x4();
		this._normalViewMatrix = $M4x4();
		this._projectionMatrix = $M4x4();
		this._invProjectionMatrix = $M4x4();
		this._worldViewProjMatrix = $M4x4();
		
		this._status = new SmitearWebGL.Core.Math.BitFlags();
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformed, false );
		this._status.setBit( SmitearWebGL.Objects.Entity.nTransformDirty, true );
	}
	,
	_destroyResource : function()
	{
		this._super();
		
		this._position = null;
		this._rotation = null;
		this._scale = null;
		this._quaternion = null;
		this._transformMatrix = null;
		this._worldMatrix = null;
		this._invWorldViewMatrix = null;
		this._worldViewMatrix = null;
		this._normalViewMatrix = null;
		this._projectionMatrix = null;
		this._worldViewProjMatrix = null;
		this._status = null;
	}
}
);

SmitearWebGL.Objects.Entity.nTransformDirty = 0;
SmitearWebGL.Objects.Entity.nTransformed = 1;
SmitearWebGL.Objects.Entity.nViewDirty = 2;
SmitearWebGL.Objects.Entity.nProjParamDirty = 3;

SmitearWebGL.Objects.Entity.DisplayType =
{
	ENTITY :	0,
	MESH :		1,
	LIGHT :		2
}